######################################################################
#
#    Author :  Ao Zhang
#    E-mail :  nlp410.cn@gmail.com
#
#    Date   :  Apr. 8, 2012
#
#    Description :
#
######################################################################

import sys
from . import words_alignment.words_alignment as words_alignment

word_sep = ' '

class rule_number:
	'''
	the number of phrase pairs
	'''
	initial_num = 0
	null_num    = 0
	total_num   = 0

class phrase_pair_extractor:
#	aligned_info_inv = []
	src_lang_length  = 0
	dst_lang_length  = 0

	def extract_phrase_pair( self,
			alignment, max_src_phrase_size, max_dst_phrase_size, null_func, rule_num ):
		src_lang_length = len( alignment.src_lang_info.words )
		dst_lang_length = len( alignment.dst_lang_info.words )
		phrase_pairs = []
		phrase_pairs_inv = []

		for dst_start in range( dst_lang_length ):
			for dst_end in range( dst_start, dst_start+max_dst_phrase_size ):
				if dst_end >= dst_lang_length:
					break
				src_start = src_lang_length
				src_end   = 0
				for i in range( dst_start, dst_end+1 ):
					for aw in alignment.dst_lang_info.align_with[i]:
						if aw < src_start:
							src_start = aw
						if aw > src_end:
							src_end = aw
				pp, ppi, rule_num = validate_phrase_pair( alignment,\
						[src_start, src_end], [dst_start, dst_end],\
						max_src_phrase_size, max_dst_phrase_size, rule_num )
				phrase_pairs.extend( pp )
				phrase_pairs_inv.extend( ppi )

		if nullfunc == '1':
			for index in range( alignment.src_lang_info.align_with ):
				if len( alignment.src_lang_info.align_with[index] ) == 0:
					rull_num.null_num += 1
					phrase_pairs.append( '%s ||| NULL ||| 0-0\n'%\
							alignment.src_lang_info.words[index] )
					phrase_pairs_inv.append( 'NULL ||| %s ||| 0-0\n'%\
							alignment.src_lang_info.words[index] )
			for index in range( alignment.dst_lang_info.align_with ):
				if len( alignment.dst_lang_info.align_with[index] ) == 0:
					rull_num.null_num += 1
					phrase_pairs.append( 'NULL ||| %s ||| 0-0\n'%\
							alignment.dst_lang_info.words[index] )
					phrase_pairs_inv.append( '%s ||| NULL ||| 0-0\n'%\
							alignment.dst_lang_info.words[index] )

		return (phrase_pairs, phrase_pairs_inv, rule_num)

	def validate_phrase_pair( self,
			alignment, src_pos, dst_pos, max_src_phrase_size, max_dst_phrase_size, rule_num):
		if src_pos[1] - src_pos[0] > max_src_phrase_size:
			return tuple()

		for i in range( src_pos[0], src_pos[1]+1 ):
			for aw in alignment.src_lang_info.align_with[i]:
				if aw < dst_pos[0] or aw > dst_pos[1]:
					return tuple()

		phrase_pairs = []
		phrase_pairs_inv = []

		src_start = src_pos[0]
		while (src_start == src_pos[0] or alignment.src_lang_info.alignment_count[src_start] == 0) \
				and src_start >= 0:
			src_end = src_pos[1]
			while src_end < self.src_lang_length \
					and ( src_end == src_pos[1] \
						or alignment.src_lang_info.alignment_count[ src_end ] == 0) \
					and src_end - src_start < max_src_phrase_size:
				pp, ppi, rule_num = add_phrase_pair( alignment,\
						[src_start, src_end], dst_pos, rule_num )
				phrase_pairs.append( pp )
				phrase_pairs_inv.append( ppi )
				src_end += 1
			src_start -= 1

		return (phrase_pairs, phrase_pairs_inv, rule_num)

	def add_phrase_pair( self, alignment, src_pos, dst_pos, rule_num ):
		src_start = src_pos[0]
		src_end   = src_pos[1]
		dst_start = dst_pos[0]
		dst_end   = dst_pos[1]

		#self.aligned_info_inv = []
		aligned_info_inv = []

		temp_dst_lang = ''
		temp_src_lang = ''

		for i in range( dst_start, dst_end+1 ) :
			for daw in alignment.dst_lang_info.align_with[i] :
				#self.aligned_info_inv.append( (i-dst_start, daw-src_start) )
				aligned_info_inv.append( (i-dst_start, daw-src_start) )
			temp_dst_lang += alignment.dst_lang_info.words[ i ] + ' '

		for i in range( src_start, src_end+1 ) :
			temp_src_lang += alignment.src_lang_info.words[ i ] + ' '

		rule_num.initial_num += 1

		phrase_pair = '%s||| %s|||'%(temp_src_lang, temp_dst_lang)
		phrase_pair_inv = '%s||| %s|||'%(temp_dst_lang, temp_src_lang)

		#for aii in self.aligned_info_inv:
		for aii in aligned_info_inv:
			phrase_pair += ' %d-%d'%(aii[1], aii[0])
			phrase_pair_inv += ' %d-%d'%(aii[0], aii[1])

		phrase_pair += '\n'
		phrase_pair_inv += '\n'

		return (phrase_pair, phrase_pair_inv, rule_num)

def main( src_file, dst_file, alignment_file, result_file, max_src_phrase_size, max_dst_phrase_size, nullfunc, encode ):
	print( phrase_extractor_logo )

	if max_src_phrase_size <= 0 or max_dst_phrase_size <= 0:
		print( '\nERROR: The max phrase size is too short.' )
		sys.exit( 1 )

	try:
		src_ifs = open( src_file, encoding = encode )
		dst_ifs = open( dst_file, encoding = encode )
		aln_ifs = open( alignment_file, encoding = encode )
		pp_ofs  = open( result_file, 'w', encoding = encode )
		ppi_ofs  = open( result_file+'.inv', 'w', encoding = encode )

		rule_num = rule_number()
		for s_line in src_ifs:
			s_line = s_line.strip()
			d_line = dst_ifs.readline().strip()
			a_line = aln_ifs.readline().strip()

			if s_line == '' or d_line == '' or a_line == '':
				print( '\nfound a blank line' )
				continue

			alignment = words_alignment()
			phrase_extractor = phrase_pair_extractor()
			if alignment.build_alignment( s_line, d_line, a_line ):
				pp, ppi, rule_num = phrase_extractor.extract_phrase_pair( alignment,\
						max_src_phrase_size, max_dst_phrase_size, nullfunc, rule_num )
				pp_ofs.writelines( pp )
				ppi_ofs.writelines( ppi )

		src_ifs.close()
		dst_ifs.close()
		aln_ifs.close()
		pp_ofs.close()
		ppi_ofs.close()
	except IOError as ie:
		print( ie )
		sys.exit( 1 )

	return True

